﻿using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using UnityEngine;
using System.Linq;
using Utility.DataSystem;
using Utility;
using Utility.Serializable;
using System;
using Utility.Math;

namespace DataSystem
{
	public class TileGroupSettingObject : SettingScriptableObject<TileGroupSetting>
	{
		[Serializable]
		public struct CellData
		{
			public static CellData Default => new CellData ()
			{
				tileIndex = -1,
				buildingIndex = -1,
				buildingOrientation = default
			};

			public int tileIndex;
			public int buildingIndex;
			public Rotation4 buildingOrientation;

		}

		public TileGroupSettingObject bilateralSymmetry_half;
		public TileGroupSetting.Categorys category = TileGroupSetting.Categorys.General;
		public bool canGainAsSupply = true;
		public int requiredMinDifficulty = 0;

		public bool canCompleteOverlap = true;
		public TileGroupSetting.OverlapTypes overlapType = TileGroupSetting.OverlapTypes.Replace;
		public TileGroupSetting.BeOverlappedTypes beOverlappedType = TileGroupSetting.BeOverlappedTypes.None;
		public List<TileSettingObject> tileSettings = new List<TileSettingObject> ();

		public Vector2Int gridSize = new Vector2Int (1, 1);
		public Vector2Int gridCenter = new Vector2Int (0, 0);

		[SerializeField]
		public CellData[] cellDataMap = new CellData[1] { CellData.Default };

		//utility
		public void SetGridSize (Vector2Int size)
		{
			if (size == gridSize)
			{
				return;
			}

			int w = size.x;
			int h = size.y;
			w = w < 1 ? 1 : w;
			h = h < 1 ? 1 : h;
			gridSize = new Vector2Int (w, h);
			cellDataMap = new CellData[w * h];
			for (int i = 0; i < cellDataMap.Length; i++)
			{
				cellDataMap[i] = CellData.Default;
			}
		}

		public void SetGridCenter (Vector2Int center)
		{
			center.x = center.x < 0 ? 0 : center.x;
			center.x = center.x >= gridSize.x ? gridSize.x - 1 : center.x;
			center.y = center.y < 0 ? 0 : center.y;
			center.y = center.y >= gridSize.y ? gridSize.y - 1 : center.y;
			gridCenter = center;
		}

		//coord
		public int CoordToIndex (Vector2Int coord)
		{
			return coord.x + gridSize.x * coord.y;
		}

		public Vector2Int IndexToCoord (int index)
		{
			int y = index / gridSize.x;
			int x = index - y * gridSize.x;
			return new Vector2Int (x, y);
		}

		//tile
		public TileSettingObject GetTileSetting (int tileIndex)
		{
			return tileSettings.TryGet (tileIndex);
		}
	}

	public class TileGroupSetting : Setting<TileGroupSettingObject>, IBuildableSetting
	{
		public enum Categorys
		{
			Ground,
			Ground_1x1,
			Platform,
			General,
			Ground_31x31,
		}

		public enum OverlapTypes
		{
			Cannot,
			Replace,
			Retain,
		}

		public enum BeOverlappedTypes
		{
			None,
			BeRemovedCompletely,
		}
		
		public OverlapTypes OverlapType => SettingObject.overlapType;
		public BeOverlappedTypes BeOverlappedType => SettingObject.beOverlappedType;
		public TileGroupSetting bilateralSymmetry_half => SettingObject.bilateralSymmetry_half?.GetSetting ();
		public int RequiredMinDifficulty => SettingObject.requiredMinDifficulty;

		protected override void Init ()
		{
			var coordCellDatas = (from i in Enumerable.Range (0, SettingObject.cellDataMap.Length)
								  let coord = SettingObject.IndexToCoord (i) - SettingObject.gridCenter
								  let celldata = SettingObject.cellDataMap[i]
								  select (coord, celldata)).ToArray ();

			TileSettings = (from pair in coordCellDatas
							let tile = SettingObject.GetTileSetting (pair.celldata.tileIndex)
							where tile != null
							select (pair.coord, tile)).ToDictionary (pair => pair.coord, pair => pair.tile.GetSetting ()).ToReadOnly ();
		}

		public Categorys Category => SettingObject.category;
		public bool CanGainAsSupply => SettingObject.canGainAsSupply;

		public bool CanCompleteOverlap => SettingObject.canCompleteOverlap;
		public ReadOnlyDictionary<Vector2Int, TileSetting> TileSettings { get; private set; }
		public ReadOnlyDictionary<Vector2Int, Rotation4> BuildingOrientations { get; private set; }
	}
}